home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
Book Chapters
/
03 - Advanced Graphics
/
Example 4 - Encoder
/
encoder.c
< prev
next >
Wrap
Text File
|
1995-03-10
|
10KB
|
361 lines
//
// File: encoder.c
//
// This file contains the routines to encode picts as shapes.
//
// 2/19/95 -- Created by Mick
//
// include files
#include "global.h"
#include <QDOffscreen.h>
#include <stdio.h>
#include "encoder.h"
#include "main.h"
// defines for this file
#define kEndShapeToken 0L // the end of shape maker
#define kLineStartToken 1L // the line start marker
#define kDrawPixelsToken 2L // the draw run marker
#define kSkipPixelsToken 3L // the skip pixels marker
#define kClearColorIndex 0 // the index of the color defined as clear (in this case, white)
// typedefs for this file
// global function declarations
void startupEncoder( void );
void shutdownEncoder( void );
void doEncode( void );
// global data owned by this file
GWorldPtr gOffscreenBuffer; // the port and gdevice of the offscreen buffer
PixMapHandle gOffscreenPixels; // the actual pixmap of the offscreen buffer
Rect gOffscreenRect = { 0, 0, 480, 640 }; // the size of the offscreen buffer
// local function declarations
static Handle encodeRect( Rect *inRect );
// static data
// functions
//
// startupEncoder -
//
// Create the buffer for the the encode routine.
//
void startupEncoder( void )
{
printf( "Allocating offscreen\n" );
// create the offscreen gworld
NewGWorld( &gOffscreenBuffer, 8, &gOffscreenRect, gAppColorTable, ( GDHandle )kNil, keepLocal );
// get the pixel map and rect
gOffscreenPixels = GetGWorldPixMap( gOffscreenBuffer );
}
//
// shutdownEncoder -
//
// Release all the memory used by the encoder.
//
void shutdownEncoder( void )
{
printf( "Disposing offscreen\n" );
// dump the offscreen gworld
DisposeGWorld( gOffscreenBuffer );
}
//
// doEncode -
//
// Encode all the PICTs from the resource fork.
//
void doEncode( void )
{
CGrafPtr oldPort; // the port in place when we started
GDHandle oldGDevice; // the gdevice in place when we started
unsigned short numResources; // the number of a type or resource ( used for both PICTs and Sprts )
unsigned short resCounter; // a counter to scan resources
Handle spriteResource; // a handle to a sprite resource
PicHandle pictResource; // a handle to a pict resource
signed short resID; // the id of the resource that we are examining
ResType resType; // the type of resource that we are examining ( needed for GetResInfo )
Str255 resName; // the name of the resource that we are examining
// save the current port and device
GetGWorld( &oldPort, &oldGDevice );
// set the offscreen
LockPixels( gOffscreenPixels );
SetGWorld( gOffscreenBuffer, ( GDHandle )kNil );
// remove all the sprite resources
printf( "Removing old sprites - " );
// determine the number of sprite resources
numResources = Count1Resources( kSpriteResType );
// if there are any,
if ( numResources != 0 )
{
// get each one,
for( resCounter = 1; resCounter <= numResources; resCounter++ )
{
// and delete it
spriteResource = Get1IndResource( kSpriteResType, resCounter );
RmveResource( spriteResource );
DisposeHandle( spriteResource );
}
}
// let the user know
printf( "Done\n" );
// determine the number of PICT resources
numResources = Count1Resources( 'PICT' );
// if there are not any,
if ( numResources == 0 )
{
// tell the user
printf( "There are no picts to encode!\n" );
}
else
{
// get each one,
for( resCounter = 1; resCounter <= numResources; resCounter++ )
{
// load the pict
pictResource = ( PicHandle )Get1IndResource( 'PICT', resCounter );
HLock( ( Handle )pictResource );
// determine its id and name
GetResInfo( ( Handle )pictResource, &resID, &resType, resName );
// let the user know what is going on
printf( "\tProcessing PICT #%d - ", resID );
// erase the background
EraseRect( &( ( *pictResource )->picFrame ) );
// draw the picture
DrawPicture( pictResource, &( ( *pictResource )->picFrame ) );
// encode the data
spriteResource = encodeRect( &( ( *pictResource )->picFrame ) );
// add the new resource to the file
AddResource( spriteResource, kSpriteResType, resID, resName );
WriteResource( spriteResource );
ReleaseResource( spriteResource );
// release the pict
ReleaseResource( ( Handle )pictResource );
// let the user know
printf( "Done\n" );
}
}
// restore the previous port and device
SetGWorld( oldPort, oldGDevice );
// unlock the pixels
UnlockPixels( gOffscreenPixels );
}
//
// encodeRect -
//
// Encode the data in the given rect into a sprite.
//
Handle encodeRect( Rect *inRect )
{
Handle shapeHandle; // the shape that we create in the function
unsigned short shapeHeight; // the height of the shape
unsigned short shapeWidth; // the width of the shape
unsigned char *destPtr; // the current position in the shape
unsigned char *srcPtr; // the current position in the souce graphic data
unsigned char *baseAddr; // the base address of the source pixmap
unsigned long rowBytes; // the row bytes of the source pixmap
unsigned char *rowStart; // the start of the current row in the pixmap
unsigned long yCounter; // a counter to scan the shape vertically
unsigned long xCounter; // a counter to scan the shape horizontally
unsigned char drawRunFlag; // are we in a draw pixels run?
unsigned char skipRunFlag; // are we in a skip pixels run?
unsigned char *lineStartPtr; // where is the line start token for this line
unsigned char *runTokenPtr; // where is the token for the current run
unsigned long runCounter; // how long is the current run?
// determine the width and height of the shape (we use these values a lot)
shapeHeight = inRect->bottom - inRect->top;
shapeWidth = inRect->right - inRect->left;
// create a handle big enough for the worst case encoding
// ( 8 bytes/pixel + 4 bytes/row + 4 bytes/shape (end token) + 8 bytes/shape (rect) )
shapeHandle = NewHandle( 8 * shapeHeight * shapeWidth + 4 * shapeHeight + 4 + 8 );
// make sure that we got the buffer
if( shapeHandle == ( Handle )kNil )
{
printf( "Error - Could not allocate buffer to build shape\n");
return shapeHandle;
}
// lock the handle and get the pointer
HLock( shapeHandle );
destPtr = ( unsigned char * )( *shapeHandle );
// store the shape rect
*( ( Rect * )destPtr ) = *inRect;
destPtr += sizeof( Rect );
// get the location of the source data
baseAddr = ( unsigned char * )GetPixBaseAddr( gOffscreenPixels );
rowBytes = ( *gOffscreenPixels )->rowBytes & 0x3fff;
rowStart = baseAddr + rowBytes * inRect->top + inRect->left;
// scan the shape row by row
for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
{
// store the location of this line start
lineStartPtr = destPtr;
destPtr += sizeof( unsigned long );
// at the beginning of each row we are not in any run
drawRunFlag = kFalse;
skipRunFlag = kFalse;
// move to the start of the row
srcPtr = rowStart;
// scan each row of the shape
for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
{
// is this pixel clear?
if ( *srcPtr == kClearColorIndex )
{
// are we in a draw run?
if ( drawRunFlag )
{
// end the draw run
drawRunFlag = kFalse;
// create the draw token
*( ( unsigned long * )runTokenPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
// pad to a mulitple of four
*( ( unsigned long * )destPtr ) = 0L;
destPtr += ( ( runCounter & 3L ) == 0 ) ? 0 : ( 4 - ( runCounter & 3L ) );
}
// are we in a skip run
if ( skipRunFlag )
{
// continue it
runCounter++;
}
else
{
// start one
skipRunFlag = kTrue;
runCounter = 1;
}
}
else
{
// are we in a skip run
if ( skipRunFlag )
{
// end the skip run
skipRunFlag = kFalse;
// create the skip token
*( ( unsigned long * )destPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
destPtr += sizeof( unsigned long );
}
// are we in a draw run
if ( drawRunFlag )
{
// continue it
runCounter++;
// copy the pixel
*destPtr = *srcPtr;
destPtr++;
}
else
{
// start one
drawRunFlag = kTrue;
runCounter = 1;
// save the location of the token (so we can fill it in later)
runTokenPtr = destPtr;
destPtr += sizeof( unsigned long );
// copy the pixel
*destPtr = *srcPtr;
destPtr++;
}
}
// move to the next byte
srcPtr++;
}
// are we in a draw run
if( drawRunFlag )
{
// end the draw run
drawRunFlag = kFalse;
// create the draw token
*( ( unsigned long * )runTokenPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
// pad to a mulitple of four
*( ( unsigned long * )destPtr ) = 0L;
destPtr += ( ( runCounter & 3L ) == 0 ) ? 0 : ( 4 - ( runCounter & 3L ) );
}
// create the line start token
*( ( unsigned long * )lineStartPtr ) = ( kLineStartToken << 24 ) + ( destPtr - ( lineStartPtr + 4 ) );
// move the row start to the next row
rowStart += rowBytes;
}
// create the end of shape token
*( ( unsigned long * )destPtr ) = kEndShapeToken << 24;
destPtr += sizeof( unsigned long );
// Unlock the handle
HUnlock( shapeHandle );
// Resize the handle to match the real size of the shape
SetHandleSize( shapeHandle, destPtr - ( unsigned char * )( *shapeHandle ) );
// return the handle
return shapeHandle;
}